
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <err.h>
#include <mcheck.h>
#include "./lib/parStr.h"
#include "./lib/cr.h"
#include "./lib/cw.h"

#include "hash.h"
#include "key.h"
#include "data.h"
#include "dict.h"
#include "pila.h"
#include "abb.h"


struct sdict {
  abb arb;
  int cant;    
};


void
dict_guardar(abb arbol, cw c2);
/* ------------------------------------------------- */

dict 
dict_empty(void)
{
  dict dr;
  
  dr=(dict)malloc(sizeof(struct sdict));
 
  dr->arb=abb_create();
  dr->cant=0;

  return dr;
}

/*
  DESC: Constructor del tipo. Crea un diccionario vacio.
  PRE: { d = NULL }
  d = dict_empty(f);
  POS: {  Hay memoria  ==> d --> empty
  ! Hay memoria  ==> d == NULL }
*/


dict
dict_fromFile(char * f)
{

  /*creo un array que contenga los elementos del archivo. */
  
  char *kk;
  char *dd;
  cr c1;
  parStr e;

  dict dicc=dict_empty();
  key kkk;
  data ddd;
  
  

  c1 = cr_create(f);

  /* No crea el archivo*/
  if (c1 == NULL)
    {
      errx(EXIT_FAILURE, "Error al crear cinta de lectura"
	   ", archivo %s, linea %i", __FILE__, __LINE__);
    }
  
  /* Arranca la cinta de lectura*/
  c1 = cr_arr(c1);
  if (c1 == NULL)
    {
      errx(EXIT_FAILURE, "Error al arrancar cinta de lectura"
	   ", archivo %s, linea %i", __FILE__, __LINE__);
    }
  
  
  /* Carga los valores contenidos en el diccionario*/
  
  while (c1 != NULL && !cr_fin(c1)) /* Si c1 es NULL es porque no pudo arrancar la cinta */
    {
      
      /* Carga la primera linea*/
      e = cr_elecor(c1);
      
      /* Si no pudo cargar la primera linea*/
      
      if (e == NULL)
	{
	  errx(EXIT_FAILURE, "No se devolvio elecorr"
	       ", archivo %s, linea %i", __FILE__, __LINE__);
	}
      
      kk=parStr_fst(e); 
      dd=parStr_snd(e); 
      kkk=key_empty();
      ddd=data_empty();

      if (kk == NULL || dd == NULL)
	{
	  errx(EXIT_FAILURE, "no se devolvio algun string" 
	       ", archivo %s, linea %i", __FILE__, __LINE__); 
	}
      
      /* Agregar los datos al array */
      assert(key_copyStr(kkk,kk));
      assert(data_copyStr(ddd,dd));
      
      dict_add(dicc,kkk,ddd);
      
	/* Libera el contenido de las variables */
	free(kk);
	free(dd); 
	kkk=key_destroy(kkk);
	ddd=data_destroy(ddd);
/*
	kkk=key_destroy(kkk);
	ddd=data_destroy(ddd);*/

  
      /*libera e*/
      e = parStr_destroy(e);
      
      /*da el avance de line*/
      cr_av(c1);
    }
  
  if (c1!=NULL)
    {
      c1 = cr_destroy(c1);	
    }
  
  return dicc;
  
}

/*
  DESC: Constructor del tipo. Crea un diccionario a partir de un archivo.
  Toma el nombre del archivo.
  PRE: { d = NULL }
  d = dict_fromFile(f);
  POS: {  Hay memoria /\ ! Error de Archivo ==> d --> fromFile(f) 
  ! Hay memoria \/   Error de Archivo ==> d == NULL }
*/

dict 
dict_destroy(dict d)
{
	if (d!=NULL)
	{  
	  (d->arb)=abb_destroy((d->arb));
	  free(d);
	  d=NULL;
	}

   return d;
}

/*
  DESC: Destructor del tipo. d cambia.
  PRE: { d --> D }
  d = dict_destroy(d);
  POS: { Se destruye D /\ d == NULL }
*/

bool
dict_toFile(char *f , const dict d)
{
  cw c2;
  /*parStr e;*/


	bool b;
 /* char *str1;
  char *str2;
	pila pil;*/
	/*abb tmparb;*/

  /*crea la cinta*/
  c2=cw_create(f);
  
  if (c2 == NULL)
    {
      errx(EXIT_FAILURE, "Error al crear cinta de escritura" 
	   ", archivo %s, linea %i", __FILE__, __LINE__);
    }
  
  /*arranca la cinta*/
  c2=cw_arr(c2);
  
  if(c2 == NULL)
    {
      errx(EXIT_FAILURE, "Error al arrancar cinta de escritura"
	   ", archivo %s, linea %i", __FILE__, __LINE__);
    }
	dict_guardar(d->arb,c2);
  

	b=(c2!=NULL);
	if (b)	
	    c2 = cw_destroy(c2);

	
		
  return b;
}

/*
  DESC: Guarda el diccionario en el archivo f.
  PRE: { d --> D }
  b = dict_toFile(f, d);
  POS: { ! Error de Archivo ==>  b /\ D guardado en archivo f 
  Error de Archivo ==> !b }
*/


dict
dict_add(dict d, const key k, const data e)
{
	/*ingresa el elemento si este no se encuentra en el diccionario
	si se encuentra regresa el mismo diccionario sin ingresar ningun elemento*/
	bool b;
	/*b=(abb_exist(k,d->arb));*/
	b=FALSE;
/*	if (!(abb_exist(k,d->arb)))*/
	if(!b)
	{
  	d->arb=abb_insert((d->arb),k,e);
  	d->cant=(d->cant)+1;
	}
    
  return d;
}

/*
  DESC: Agrega en el diccionario el dato d con la clave k.
  Si la clave ya existe no hace nada.
  Si agrega no utiliza k ni e (copia).
  PRE: { d --> D /\ k --> K /\ e --> E /\ !exist(D,K)}
  d = dict_add(d, k, e);
  POS: { d --> add(D,K,E) }
*/

bool
dict_exist(const dict d, const key k)
{
  if (d->cant==0)
		return FALSE;
  else
  	return (abb_exist(k,d->arb));
}

/*
  DESC: Busca el dato con clave k si existe. Si no existe devuelve False.
  PRE: { d --> D /\ k --> K }
  b = dict_exist(d, k);
  POS: { (D =  add(D',K,E) /\ b ) \/ 
  (D != add(D',K,E) /\ !b ) }
*/

data
dict_search(const dict d, const key k)
{

  /*  i=lsearch(d,k);*/
	bool b;
	b=abb_exist(k,d->arb);
  if (b)
    {
    	return (abb_search(k, (d->arb)));
    }
  else
    {   
      return NULL;
    }

}


/*
  DESC: Busca y trae el dato con clave k si existe. Si no devuelve NULL.
  Crea copia del dato.
  PRE: { d --> D /\ k --> K /\ e = NULL }
  e = dict_search(d, k);
  POS: { (D =  add(D',K,E) /\ e --> E ) \/ 
  (D != add(D',K,E) /\ e = NULL ) }
*/

dict
dict_del(dict d, const key k)
{

  if (abb_exist(k,(d->arb)))
  {
    d->arb=abb_del((d->arb),k);
   (d->cant)-=1;
  }

  return d;
}

/*
  DESC: Borra el dato con clave k. Si no esta devuelve null. 
  Destruye contenidos.
  PRE: { d --> D /\ k --> K /\ e = NULL }
  d = dict_del(d, k);
  POS: { ( D  = add(D',K,E) /\ d --> D') \/
  ( D != add(D',K,E) /\ d --> D }
*/

int
dict_length(dict d)
{
  return (d->cant);
}

/*
  DESC: Devuelve la cantidad de estradas en el diccionario. 
  PRE: { d --> D }
  l = dict_length(d);
  POS: { l = length(D) }
*/


void
dict_guardar(abb arbol, cw c2)
{
	char *str1;
	char *str2;
	parStr e;
	
	if (!(abb_is_empty(arbol)))
	{
		str1=key_toStr(abb_root_key(arbol));
		str2=data_toStr(abb_root_data(arbol));
	}

   e=parStr_create(str1,str2);
/*avanzo la cinta */

   
      
    	  if (e == NULL)
				{
	  		errx(EXIT_FAILURE, "No se devolvio elecor"
	  	     ", archivo %s, linea %i", __FILE__, __LINE__);
				}
	  
      
	c2 = cw_insert(c2, e);
   e = parStr_destroy(e);

      
	free(str1);
   free(str2);
				
	if (has_right(arbol))
		dict_guardar(abb_right(arbol),c2);
	if (has_left(arbol))
		dict_guardar(abb_left(arbol),c2);

}
